package com.lmq.matchingsystem.service.impl.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

@Component
public class MatchingPool extends Thread {
    private static List<Player> players = new ArrayList<>();
    private ReentrantLock mtx = new ReentrantLock();

    private final String startGameUrl = "http://127.0.0.1:8999/pk/start/game/";
    private static RestTemplate restTemplate;

    @Autowired
    private void setRestTemplate(RestTemplate restTemplate) {
        MatchingPool.restTemplate = restTemplate;
    }

    public void addPlayer(Integer userId, Integer rating, Integer botId) {
        mtx.lock();
        try {
            players.add(new Player(userId, rating, botId, 0));
        } finally {
            mtx.unlock();
        }
    }

    public void removePlayer(Integer userId) {
        mtx.lock();
        try {
            players.removeIf(player -> player.getUserId().equals(userId));
        } finally {
            mtx.unlock();
        }
    }

    private void increaseTime() {
        for(Player player : players) {
            player.setWaitingTime(player.getWaitingTime() + 1);
        }
    }

    private boolean check(Player playerA, Player playerB) {
        int diff = Math.abs(playerA.getRating() - playerB.getRating());
        int waitTime = Math.min(playerA.getWaitingTime(), playerB.getWaitingTime());
        return diff <= waitTime * 10;
    }

    private void sendResult(Player playerA, Player playerB) {
        System.out.println("result: " + playerA + " and " + playerB);
        MultiValueMap<String, String> res = new LinkedMultiValueMap<>();
        res.add("a_id", playerA.getUserId().toString());
        res.add("a_bot_id", playerA.getBotId().toString());
        res.add("b_id", playerB.getUserId().toString());
        res.add("b_bot_id", playerB.getBotId().toString());
        restTemplate.postForObject(startGameUrl, res, String.class);
    }

    private void match() {
        boolean[] used = new boolean[players.size()];
        for(int i = 0; i < players.size(); i++) {
            if(used[i]) continue;
            for(int j = i + 1; j < players.size(); j++) {
                if(used[j]) continue;
                Player playerA = players.get(i);
                Player playerB = players.get(j);
                if(check(playerA, playerB)) {
                    used[i] = true;
                    used[j] = true;
                    sendResult(playerA, playerB);
                }
            }
        }

        List<Player> newPlayers = new ArrayList<>();
        for(int i = 0; i < players.size(); i++) {
            if(!used[i]) {
                newPlayers.add(players.get(i));
            }
        }
        players = newPlayers;
    }

    @Override
    public void run() {
        while(true) {
            try {
                Thread.sleep(1000);
                mtx.lock();
                try {
                    increaseTime();
                    match();
                } finally {
                    mtx.unlock();
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
